﻿using Binding;
using DistributedExample;
using Net.Event;
using Net.Helper;
using Net.System;
using System.Diagnostics;
using Wordgames;
using WordGames.Service;
using WordGames.System;

namespace WordGames
{
    internal class Program
    {
        static void Main(string[] args)
        {
            MySQLHelper.Inject();
            NDebug.WriteFileMode = WriteLogMode.Error;
            NDebug.BindConsoleLog(false, 100000);
            Fast2BuildMethod.DynamicBuild(SerializeMode.Compress, 1, BindingTypeDefinition.GetTypes);
            DataCacheManager.Instance.Start();
            WordgamesDB.IsDistributed = true;
            ClusterSystem.Config = PersistHelper.Deserialize("config.ini", new Config()
            {
                /*Local = //本机配置
                [
                    new LocalConfig()
                    {
                        Name = "WordGames.GateService",
                        Hosts = ["127.0.0.1:5000", "127.0.0.1:5001"]
                    },
                    new LocalConfig()
                    {
                        Name = "WordGames.LoginService",
                        Hosts = ["127.0.0.1:6000", "127.0.0.1:6001"]
                    },
                    new LocalConfig()
                    {
                        Name = "WordGames.GameService",
                        Hosts = ["127.0.0.1:7000", "127.0.0.1:7001"]
                    }
                ],*/
                Cluster = //集群配置
                [
                    new ClusterConfig()
                    {
                        Name = "WordGames.LoginService",
                        Nodes = ["127.0.0.1:6000", "127.0.0.1:6001"]
                    },
                    new ClusterConfig()
                    {
                        Name = "WordGames.GameService",
                        Nodes = ["127.0.0.1:7000", "127.0.0.1:7001"]
                    }
                ],
                DBConfig =
                [
                    new DBConfig()
                    {
                        DBName = "GameDB_01",
                        User = "root",
                        Password = "root",
                        MachineId = 1,
                        Host = "127.0.0.1:3306",
                    },
                    new DBConfig()
                    {
                        DBName = "GameDB_02",
                        User = "root",
                        Password = "root",
                        MachineId = 2,
                        Host = "127.0.0.1:3306",
                    }
                ],
                CentralHost = "127.0.0.1:10240",
                ServerConfig = new Net.Config.ServerConfig()
                {
                    LimitQueueCount = 10000000,
                    PackageLength = 10000000,
                    PackageSize = 1024 * 1024 * 50,
                    SendBufferSize = 1024 * 1024 * 10,
                    ReceiveBufferSize = 1024 * 1024 * 10,
                },
                ClientConfig = new Net.Config.ClientConfig()
                {
                    LimitQueueCount = 10000000,
                    PackageLength = 10000000,
                    PackageSize = 1024 * 1024 * 50,
                    SendBufferSize = 1024 * 1024 * 10,
                    ReceiveBufferSize = 1024 * 1024 * 10,
                    ReconnectCount = int.MaxValue,
                }
            }, true);
            ClusterSystem.StartDBCluster(); //解决同时创建数据库的问题
            if (args.Length == 0)
            {
                Start();
                goto J;
            }
            StartService(args);
        J: while (true)
            {
                Thread.Sleep(1000);
            }
        }

        private static async void Start()
        {
            var color = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("运行此分布式案例前需要安装Mysql (推荐8.0.28版本，群文件有)\r\n" +
                "如果mysql的连接用户是root并且密码是root则直接运行！\r\n" +
                "如果不是，你需要修改Program.cs文件第56行的DBConfig的密码后再运行！\r\n");
            Console.ForegroundColor = color;
            Console.WriteLine("选择服务器模式:");
            Console.WriteLine("1.单进程");
            Console.WriteLine("2.多进程");
            Console.WriteLine("3.数据库动态扩缩容");
            Console.WriteLine("---------------------------------------------------------------------------------------------");
            Console.WriteLine("模拟服务器崩溃重启，你先使用2启动多个进程，然后再关闭几个服务器，再使用以下命令启动单个服务器");
            Console.WriteLine("  输入:CentralServer重启中心服务器");
            Console.WriteLine("  输入:GateService 5000重启1号网关服务器");
            Console.WriteLine("  输入:GateService 5001重启2号网关服务器");
            Console.WriteLine("  输入:LoginService 6000 GameDB_01重启1号登录服务器");
            Console.WriteLine("  输入:LoginService 6001 GameDB_02重启2号登录服务器");
            Console.WriteLine("  输入:GameService 7000 GameDB_01重启1号登录服务器");
            Console.WriteLine("  输入:GameService 7001 GameDB_02重启2号登录服务器");
            Console.WriteLine("  输入:Client 5000 启动测试客户端并且连接网关5000端口的服务器");
            Console.WriteLine("  输入:Client 5001 启动测试客户端并且连接网关5001端口的服务器");
            Console.WriteLine("  输入:MultiClient 5000 5001 100 启动100个客户端并且随机连接网关5000和5001端口的服务器");
            Console.WriteLine("---------------------------------------------------------------------------------------------");
            while (true)
            {
                var command = Console.ReadLine();
                if (command.StartsWith("1") | command.StartsWith("2"))
                {
                    //先启动配置服务器
                    StartNewProcess("CentralServer", command == "2");
                    await Task.Delay(1000);
                    //启动登录服务器
                    StartNewProcess("LoginService 6000 GameDB_01", command == "2");
                    StartNewProcess("LoginService 6001 GameDB_02", command == "2");
                    //启动游戏服务器
                    StartNewProcess("GameService 7000 GameDB_01", command == "2");
                    StartNewProcess("GameService 7001 GameDB_02", command == "2");
                    //启动网关服务器
                    StartNewProcess("GateService 5000", command == "2");
                    StartNewProcess("GateService 5001", command == "2");
                    //启动客户端
                    //StartNewProcess("Client 5000", command == "2");
                    StartNewProcess("MultiClient 5000 5001 1000", command == "2");
                    if (command == "2")
                        StartNewProcess("Client 5001", command == "2");
                    if (command == "1")
                        break;
                }
                else if (command.StartsWith("3"))
                {
                    //先启动配置服务器
                    StartNewProcess("CentralServer", command == "2");
                    await Task.Delay(1000);
                    //启动客户端
                    StartNewProcess("DBManager", command == "2");
                    break;
                }
                else if (command.StartsWith("CentralServer") |
                    command.StartsWith("GateService") |
                    command.StartsWith("LoginService") |
                    command.StartsWith("GameService") |
                    command.StartsWith("Client") |
                    command.StartsWith("MultiClient"))
                {
                    StartNewProcess(command, true);
                }
            }
        }

        private static void StartNewProcess(string args, bool multiProcess)
        {
            if (multiProcess)
            {
                var appPath = Environment.ProcessPath;
                var startInfo = new ProcessStartInfo
                {
                    FileName = appPath,
                    Arguments = args,
                    CreateNoWindow = false,
                    UseShellExecute = true
                };
                Process.Start(startInfo);
            }
            else
            {
                StartService(args.Split(' '));
            }
        }

        static void StartService(string[] args)
        {
            switch (args[0])
            {
                case "CentralServer":
                    var centralServer = new CentralServer();
                    centralServer.AddAdapter(new Net.Adapter.SerializeAdapter3());
                    centralServer.Start(10240);
                    break;
                case "DBService":
                    StartCluster(new LocalConfig()
                    {
                        Name = "WordGames.DBService",
                        Hosts = [new($"127.0.0.1:{args[1]}", args[2])]
                    });
                    break;
                case "LoginService":
                    StartCluster(new LocalConfig()
                    {
                        Name = "WordGames.LoginService",
                        Hosts = [new($"127.0.0.1:{args[1]}", args[2])]
                    });
                    break;
                case "GameService":
                    StartCluster(new LocalConfig()
                    {
                        Name = "WordGames.GameService",
                        Hosts = [new($"127.0.0.1:{args[1]}", args[2])]
                    });
                    break;
                case "GateService":
                    StartCluster(new LocalConfig()
                    {
                        Name = "WordGames.GateService",
                        Hosts = [new($"127.0.0.1:{args[1]}")]
                    });
                    break;
                case "Client":
                    var clientTest = new ClientTest();
                    clientTest.Init(int.Parse(args[1]));
                    break;
                case "MultiClient":
                    var multiClientTest = new MultiClientTest();
                    multiClientTest.Init(int.Parse(args[1]), int.Parse(args[2]), int.Parse(args[3]));
                    break;
                case "DBManager":
                    ClusterSystem.StartDBCluster();
                    var dbManager = new DBManager();
                    dbManager.Init();
                    break;
            }
        }

        static void StartCluster(params LocalConfig[] locals)
        {
            ClusterSystem.Config.Local = new List<LocalConfig>(locals);
            ClusterSystem.Start();
        }
    }
}